package com.stylefeng.guns.config.web;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.druid.support.spring.stat.BeanTypeAutoProxyCreator;
import com.alibaba.druid.support.spring.stat.DruidStatInterceptor;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import com.stylefeng.guns.GunsApplication;
import com.stylefeng.guns.config.properties.GunsProperties;
import com.stylefeng.guns.core.intercept.RestApiInteceptor;
import com.stylefeng.guns.core.listener.ConfigListener;
import com.stylefeng.guns.core.xss.XssFilter;
import java.io.File;
import org.springframework.aop.Advisor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.JdkRegexpMethodPointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.system.ApplicationHome;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.context.request.RequestContextListener;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

import java.util.Arrays;
import java.util.Properties;

/**
 * web 配置类
 *
 * @author fengshuonan
 * @date 2016年11月12日 下午5:03:32
 */
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {

  @Autowired
  private GunsProperties gunsProperties;

  /**
   * 增加swagger的支持
   */
  @Override
  public void addResourceHandlers(ResourceHandlerRegistry registry) {
    if (gunsProperties.getSwaggerOpen()) {
      registry.addResourceHandler("swagger-ui.html")
              .addResourceLocations("classpath:/META-INF/resources/");
      registry.addResourceHandler("/webjars/**")
              .addResourceLocations("classpath:/META-INF/resources/webjars/");
    }

    File home = new ApplicationHome(GunsApplication.class).getDir();
    String modelPath = "file:///" + home + "/models/";
    registry.addResourceHandler("/sketchup/**").addResourceLocations(
        modelPath);
    registry.addResourceHandler("/sketchup/texture/**").addResourceLocations(
        "file:///" + home + "/skm/textures/");
  }

  /**
   * 增加对rest api鉴权的spring mvc拦截器
   */
  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new RestApiInteceptor()).addPathPatterns("/gunsApi/**");
  }

  /**
   * druidServlet注册
   */
  @Bean
  public ServletRegistrationBean druidServletRegistration() {
    ServletRegistrationBean registration = new ServletRegistrationBean(new StatViewServlet());
    registration.addUrlMappings("/druid/*");
    return registration;
  }

  /**
   * druid监控 配置URI拦截策略
   */
  @Bean
  public FilterRegistrationBean druidStatFilter() {
    FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
    //添加过滤规则.
    filterRegistrationBean.addUrlPatterns("/*");
    //添加不需要忽略的格式信息.
    filterRegistrationBean.addInitParameter(
        "exclusions", "/static/*,*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid,/druid/*");
    //用于session监控页面的用户名显示 需要登录后主动将username注入到session里
    filterRegistrationBean.addInitParameter("principalSessionName", "username");
    return filterRegistrationBean;
  }

  /**
   * druid数据库连接池监控
   */
  @Bean
  public DruidStatInterceptor druidStatInterceptor() {
    return new DruidStatInterceptor();
  }

  @Bean
  public JdkRegexpMethodPointcut druidStatPointcut() {
    JdkRegexpMethodPointcut druidStatPointcut = new JdkRegexpMethodPointcut();
    String patterns = "com.stylefeng.guns.modular.*.service.*";
    //可以set多个
    druidStatPointcut.setPatterns(patterns);
    return druidStatPointcut;
  }

  /**
   * druid数据库连接池监控
   */
  @Bean
  public BeanTypeAutoProxyCreator beanTypeAutoProxyCreator() {
    BeanTypeAutoProxyCreator beanTypeAutoProxyCreator = new BeanTypeAutoProxyCreator();
    beanTypeAutoProxyCreator.setTargetBeanType(DruidDataSource.class);
    beanTypeAutoProxyCreator.setInterceptorNames("druidStatInterceptor");
    return beanTypeAutoProxyCreator;
  }

  /**
   * druid 为druidStatPointcut添加拦截
   */
  @Bean
  public Advisor druidStatAdvisor() {
    return new DefaultPointcutAdvisor(druidStatPointcut(), druidStatInterceptor());
  }

  /**
   * xssFilter注册
   */
  @Bean
  public FilterRegistrationBean xssFilterRegistration() {
    XssFilter xssFilter = new XssFilter();
    xssFilter.setUrlExclusion(Arrays.asList("/notice/update", "/notice/add"));
    FilterRegistrationBean registration = new FilterRegistrationBean(xssFilter);
    registration.addUrlPatterns("/*");
    return registration;
  }

  /**
   * RequestContextListener注册
   */
  @Bean
  public ServletListenerRegistrationBean<RequestContextListener> requestContextListenerRegistration() {
    return new ServletListenerRegistrationBean<>(new RequestContextListener());
  }

  /**
   * ConfigListener注册
   */
  @Bean
  public ServletListenerRegistrationBean<ConfigListener> configListenerRegistration() {
    return new ServletListenerRegistrationBean<>(new ConfigListener());
  }

  /**
   * 验证码生成相关
   */
  @Bean
  public DefaultKaptcha kaptcha() {
    Properties properties = new Properties();
    properties.put("kaptcha.border", "no");
    properties.put("kaptcha.border.color", "105,179,90");
    properties.put("kaptcha.textproducer.font.color", "blue");
    properties.put("kaptcha.image.width", "125");
    properties.put("kaptcha.image.height", "45");
    properties.put("kaptcha.textproducer.font.size", "45");
    properties.put("kaptcha.session.key", "code");
    properties.put("kaptcha.textproducer.char.length", "4");
    properties.put("kaptcha.textproducer.font.names", "宋体,楷体,微软雅黑");
    Config config = new Config(properties);
    DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
    defaultKaptcha.setConfig(config);
    return defaultKaptcha;
  }
}
